<?php
class nl_ftp
{
    //FTP 主机
    private $host = null;
    //FTP 账号
    private $user = null;
    //FTP 密码
    private $password = null;
    //FTP 超时时间
    private $time_out = null;
    //FTP 端口
    private $port = null;
    //FTP 错误描述
    private $error_desc = null;
    //FTP ftp链接
    private $ftp_conn = null;
    //ftp上的文件列表
    private $arr_file_list = null;
    //
    private $ftp_pasv = FALSE;
    
    private $all_files = array();

    private $int_num = 0;
    
    /**
     * @return the $arr_file_list
     */
    public function get_arr_file_list()
    {
        return $this->arr_file_list;
    }

    /**
     * @param unknown $user
     * @param unknown $password
     * @param string $port
     */
    public function __construct($host=null,$user=null,$password=null,$port=21,$time_out=90,$ftp_pasv = FALSE,$ftp_all_url='')
    {
        $this->error_desc=null;
        if($host === null && strlen($ftp_all_url) >0)
        {
            $this->parse_ftp_url($ftp_all_url);
        }
        else
        {
            $this->host = $host;
            $this->user = $user;
            $this->password = $password;
            $this->port = $port;
        }
        $this->time_out = $time_out;
        $this->ftp_pasv = $ftp_pasv;
    }
    
    
    /**
     * 解析ftp地址
     * @param unknown $ftp_url
     */
    public function parse_ftp_url($ftp_url)
    {
        $ftp_url = trim($ftp_url,'/');
        $arr_ftp_config = parse_url($ftp_url);
        $host_ftp = (isset($arr_ftp_config["host"]) && strlen($arr_ftp_config["host"]) > 0) ? $arr_ftp_config["host"] : '';
        $user_ftp = (isset($arr_ftp_config["user"]) && strlen($arr_ftp_config["user"]) > 0) ? $arr_ftp_config["user"] : '';
        $pass_ftp = (isset($arr_ftp_config["pass"]) && strlen($arr_ftp_config["pass"]) > 0) ? $arr_ftp_config["pass"] : '';
        $path_ftp = (isset($arr_ftp_config["path"]) && strlen($arr_ftp_config["path"]) > 0) ? $arr_ftp_config["path"] : '';
        $port_ftp = (isset($arr_ftp_config["port"]) && strlen($arr_ftp_config["port"]) > 0) ? $arr_ftp_config["port"] : 21;
        $this->host = $host_ftp;
        $this->user = $user_ftp;
        $this->password = $pass_ftp;
        $this->port = $port_ftp;
        $this->path = $path_ftp;
        return true;
    }
    
    /**
     * ftp基本操作
     * @return multitype:number
     */
    public function base_opration_ftp()
    {
        if(empty($this->host))
        {
            $this->set_error_desc("FTP链接地址为空:".var_export($this->host));
            return false;
        }
        if(strlen($this->user) <1)
        {
            $this->set_error_desc("FTP账号为空:".var_export($this->user));
            return false;
        }
        if(strlen($this->password) <1)
        {
            $this->set_error_desc("FTP密码为空:".var_export($this->password));
            return false;
        }
        if(!$this->check_conn())
        {
            return false;
        }
        if(!$this->check_login())
        {
            return false;
        }
        return true;
    }
    
    /**
     * @return the $error_desc
     */
    private function get_error_desc()
    {
        return $this->error_desc;
    }
    
    /**
     * @param field_type $error_desc
     */
    private function set_error_desc($error_desc)
    {
        $this->error_desc[] = $error_desc;
    }
    
    /**
     * 反馈正确数据
     * @param string $data_info
     * @return multitype:number string
     */
    private function make_right_data($data_info=null)
    {
        return array(
            'ret'=>0,
            'reason'=>'ok',
            'data_info'=>$data_info
        );
    }
    
    /**
     * 反馈错误数据
     * @return multitype:number string
     */
    public function make_error_data()
    {
        return array(
            'ret'=>1,
            'reason'=>implode(',',$this->get_error_desc()),
        );
    }
    
    /**
     * FTP 链接
     * @return boolean
     */
    private function check_conn()
    {
        $obj_conn = ftp_connect($this->host,$this->port,$this->time_out);
        if(!$obj_conn)
        {
            $this->set_error_desc("FTP链接失败,链接参数,主机[{$this->host}],端口[{$this->port}],超时时间[{$this->time_out}]");
            return false;
        }
        $this->ftp_conn = $obj_conn;
        unset($obj_conn);
        return true;
    }
    
    
    public function ftp_recursive_file_listing($path = '/',$str_extension='')
    {
        $str_extension = trim($str_extension);
        $str_extension = strlen($str_extension) > 0 ? strtolower($str_extension) : '';
        $contents = ftp_nlist($this->ftp_conn, $path);
        usleep(50000);
        if(empty($contents) || !is_array($contents))
        {
            return null;
        }

        //m_config::base_write_log('message','request',date('Y-m-d H:i:s') . ' 文件夹数量【' . $this->int_num . '】。地址：' . addslashes($path));

        echo ++ $this->int_num . ',';

        foreach ($contents as $currentFile) 
        {
            if (strpos($currentFile, '.') === false) 
            {
                $this->ftp_recursive_file_listing($currentFile,$str_extension);
            }
            $file_name = substr($currentFile, strlen($path));
            if(strlen($str_extension) >0)
            {
                $temp_file_url = pathinfo($file_name);
                if(!isset($temp_file_url['extension']) || strtolower($temp_file_url['extension']) != $str_extension)
                {
                    continue;
                }
            }
            $this->all_files[$path][] = $file_name;
        }
        unset($contents);
        return $this->all_files;
    }
    
    
    /**
     * FTP 登录
     * @return boolean
     */
    private function check_login()
    {
        $flag_login = ftp_login($this->ftp_conn, $this->user, $this->password);
        if(!$flag_login)
        {
            $this->set_error_desc("FTP用户验证失败,账号[{$this->user}],密码[{$this->password}]");
            return false;
        }
        if($this->ftp_pasv)
        {
            ftp_pasv($this->ftp_conn,true);
        }
        return true;
    }
    
    /**
     * 创建FTP文件夹
     * @param unknown $str_dir
     */
    public function make_dir($str_dir)
    {
        $result_base = $this->base_opration_ftp();
        if(!$result_base)
        {
            return $this->make_error_data();
        }
        $str_dir = str_replace('//', '/', $str_dir);
        $str_dir = str_replace('//', '/', $str_dir);
        $str_dir = trim($str_dir,'/');
        $parts = explode("/",$str_dir);
        if(!is_array($parts) || empty($parts))
        {
             return $this->make_right_data();
        }
        $fullpath = "";
        foreach($parts as $part)
        {
            if(strlen($part) <1)
            {
                $fullpath .= "/";
                continue;
            }
            $fullpath .= $part."/";
            if(!$this->ftp_directory_exists($fullpath))
            {
                if(!$this->make_ftp_dir($fullpath))
                {
                    return $this->make_error_data();
                }
            }
        }
        return $this->make_right_data();
    }
    
    /**
     * 检查文件目录是否存在
     * @param unknown $dir
     * @return boolean
     */
    private function ftp_directory_exists($dir)
    {
        $origin = ftp_pwd($this->ftp_conn);
        if (@ftp_chdir($this->ftp_conn, $dir))
        {
            $result = @ftp_chdir($this->ftp_conn, $origin);
            return true;
        }
        return false;
    }
    
    /**
     * 创建ftp文件夹
     * @param unknown $str_dir
     */
    private function make_ftp_dir($str_dir)
    {
        if(@ftp_mkdir($this->ftp_conn, $str_dir))
        {
            @ftp_chmod($this->connect_no, 0777, $str_dir);
            return true;
        }
        $this->set_error_desc("FTP创建文件夹失败,路径[{$str_dir}]".var_dump($this->ftp_conn));
        return false;
    }
    
    
    /**
     * 更改文件权限    这儿暂时不做报错处理（条件先暂时放宽，后期增加）
     * @param unknown $file
     * @param string $chod_mode
     */
    private function make_chmod($file,$chod_mode='0777')
    {
        return ftp_chmod($this->ftp_conn,$chod_mode,$file);
    }

    /**
     * 删除文件
     * @param string  $delete_file            需要删除的文件
     * @param boolean $delete_empty_dir_flag  是否删除文件所在的文件夹（文件夹为空）
     * @param int     $delete_dir_num         删除几层结构 （1表示删除此文件的父级，2表示删除父级的上层文件夹，以此类推）
     * @return array  array('ret'=>'返回码/0为成功其他为失败','reason'=>'返回码的文字说明','data_info'=>'返回的数据信息')
     * @author feijian.gao [2016年12月9日18:07:55]
     */
    public function delete_file($delete_file, $delete_empty_dir_flag = false, $delete_dir_num = 0)
    {
        //获取ftp资源流
        $result_base = $this->base_opration_ftp();
        if(!$result_base)
        {
            return $this->make_error_data();
        }

        //处理需要删除的文件路径
        $delete_file = str_replace('//', '/', $delete_file);

        //删除文件
        $result = $this->delete_ftp_file($delete_file);
        if(!$result)
        {
            return $this->make_error_data();
        }

        //判断当前文件夹是否为空，若为空删除空文件夹
        if($delete_empty_dir_flag)
        {
            while($delete_dir_num > 0)
            {
                $num = strrpos($delete_file, '/');
                $current_directory = substr($delete_file,0,$num);
                $result = $this->check_directory_empty($current_directory);

                if(!empty($result))
                {
                   $this->error_desc = '[文件夹不为空无法删除]'.var_export($current_directory);
                    return $this->make_error_data();
                }

                $result = $this->delete_ftp_directory($current_directory);
                if(!$result)
                {
                    return $this->make_error_data();
                }

                $delete_file = $current_directory;
                $delete_dir_num--;
            }
        }

        return $this->make_right_data();
    }


    /**
     * @param $delete_file
     * @return bool
     */
    private function delete_ftp_file($delete_file)
    {
        $result = @ftp_delete($this->ftp_conn, $delete_file);

        if(!$result)
        {
            $this->error_desc = '[文件删除失败,请检查文件是否存在或权限]'.var_export($this->ftp_conn,true);
            return false;
        }
        return true;
    }

    /**
     * 删除文件夹
     * @param string    $directory     要删除的文件夹
     * @param boolean   $force_delete  若文件夹不为空，是否强制删除文件夹内的文件，之后再删除该文件夹
     * @return array    array('ret'=>'返回码/0为成功其他为失败','reason'=>'返回码的文字说明','data_info'=>'返回的数据信息')
     * @author feijian.gao [2016年12月9日18:07:55]
     */
    public function delete_directory($directory, $force_delete=false)
    {
        //获取ftp资源流
        $result_base = $this->base_opration_ftp();
        if(!$result_base)
        {
            return $this->make_error_data();
        }

        //判断文件夹是否存在
        $result = $this->ftp_directory_exists($directory);
        if(!$result)
        {
            $this->error_desc = '[文件夹不存在]'.var_export($this->ftp_conn, true);
            return $this->make_error_data();
        }

        //判断目录内是否为空（只有空目录才能删除)
        $files = $this->check_directory_empty($directory);

        if(count($files) > 0 && $force_delete == false)
        {
            $this->error_desc = '[文件夹不为空，无法删除]'.var_export($this->ftp_conn,true);
            return $this->make_error_data();
        }

        //循环删除非空文件夹内的文件
        if(is_array($files) && $force_delete == true)
        {
            //循环删除目录中文件
            foreach ($files as $file) {
                $file = $directory.'/'.$file;
                $this->delete_ftp_file($file);
            }
        }

        //文件内的内容删除之后，删除文件夹
        $result = $this->delete_ftp_directory($directory);
        if(!$result)
        {
            return $this->make_error_data();
        }
        return $this->make_right_data();
    }

    /**
     * @param $directory
     * @return bool
     */
    private function delete_ftp_directory($directory)
    {
        $result = @ftp_rmdir($this->ftp_conn,$directory);
        if(!$result)
        {
            $this->error_desc = '[删除文件夹失败]'.var_export($this->ftp_conn, true);
        }
        return $result;
    }

    /**
     * 检查文件夹是否为空
     * @param $directory
     * @return mixed
     */
    private function check_directory_empty($directory)
    {
        $result = ftp_nlist($this->ftp_conn, $directory);

        if(is_array($result))
        {
            return $result;
        }
        return false;
    }

    /**获取ftp当前目录中的文件列表
     * @param  string  $str_directory  文件目录
     * @return mixed|multitype          若目录内文件不为空，返回文件名称的数据，反之则为false
     *     返回数据说明: array=array('0'=>'文件名0','1'=>'文件名1','2'=>'文件名2','3'=>'文件名3');
     *                   boolean=false 目录不合法或者目录内文件为空
     * @author  feijian.gao
     * @date    2017-1-19 19:16:14
     */
    public function get_directory_file_list($str_directory)
    {
        //获取ftp资源流
        $result_base = $this->base_opration_ftp();
        if(!$result_base)
        {
            return $this->make_error_data();
        }
        $result = $this->check_directory_empty($str_directory);
        return $result;
    }
    
    public function get_all_file($str_directory)
    {
        //获取ftp资源流
        $result_base = $this->base_opration_ftp();
        if(!$result_base)
        {
            return $this->make_error_data();
        }
        $result = $this->list_dir($str_directory);
        return $result;
    }

    public function make_file($str_directory,$result)
    {
        static $last_files = array();
        if(isset($result['files']) && is_array($result['files']) && !empty($result['files']))
        {
            foreach ($result['files'] as $val)
            {
                $val['url'] = $str_directory.$val['name'];
                $last_files[] = $last_files;
            }
        }
        if(isset($result['folders']) && is_array($result['folders']) && !empty($result['folders']))
        {
            foreach ($result['folders'] as $val)
            {
                $this->make_file($str_directory.$val['name'], $this->list_dir($str_directory.$val['name']));
            }
        }
        return $last_files;
    }
  
    /**
     * 列出ftp清单文件
     * @param unknown $obj_ftp
     * @param unknown $path
     */
    public function ftp_list_file($path,$num=0)
    {
        $temp_num = $num;
        $result = $this->get_directory_file_list($path);

        if(!is_array($result) || empty($result))
        {
            return ;
        }
        foreach ($result as $val)
        {
            if($this->ftp_is_dir_v2($val))
            {
                if($num == $temp_num)
                {
                    $num++;
                }
                $this->ftp_list_file($val,$num);
            }
            else
            {
                $this->arr_file_list[$temp_num][]=array('url' => iconv(mb_detect_encoding($val, array('GBK', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'ISO-8859-1')), 'UTF-8',$val ),'size'=>ftp_size($this->ftp_conn,$val));
            }
        }
        return ;
    }
    
    
    public function ftp_is_dir($dir)
    {
        if (@ftp_chdir($this->ftp_conn, basename($dir))) 
        {
            ftp_chdir($this->ftp_conn, '..');
            return true;
        } 
        else
        {
            return false;
        }
    }
    
    public function ftp_is_dir_v2($dir)
    {
        if (@ftp_chdir($this->ftp_conn, $dir))
        {
            ftp_chdir($this->ftp_conn, '..');
            return true;
        }
        else
        {
            return false;
        }
    }
    
    
    public function list_dir($dir,$recursive=null)
    {
        $return_arr =array();
        $list_arr = ftp_rawlist($this->ftp_conn,$dir,$recursive);
        if(!empty($list_arr) && is_array($list_arr))
        {
            $folders = $links=$files=array();
            foreach($list_arr as $item)
            {
                $current = preg_split('/[\s]+/',$item,9);
                $struc['perms']    = $current[0];
                $struc['permsn']= $current[0];
                $struc['number']= $current[1];
                $struc['owner']    = $current[2];
                $struc['group']    = $current[3];
                $struc['size']    = $current[4];
                $struc['month']    = $current[5];
                $struc['day']    = $current[6];
                $struc['time']    = $current[7];
                $struc['name']    = str_replace('//','',$current[8]);
                if ($struc['name'] != '.' && $struc['name'] != '..' && substr($struc['perms'], 0, 1) == "d")
                {
                    $folders[] = $struc;
                }
                elseif ($struc['name'] != '.' && $struc['name'] != '..' && substr($struc['perms'], 0, 1) == "l")
                {
                    $links[] = $struc;
                }
                elseif ($struc['name'] != '.' && $struc['name'] != '..')
                {
                    $files[] = $struc;
                }
            }
            $return_arr['files'] = $files;
            $return_arr['folders'] = $folders;
            $return_arr['links'] = $links;
        }
        return $return_arr;
    }
    
    /**
     * 上传文件
     */
    public function upload_file($remote_file,$source_file)
    {
        $remote_file = str_replace('//','/',$remote_file);
        $source_file = str_replace('//','/',$source_file);
        $arr_data = array(
            'remote_path'=>$remote_file,
            'source_file'=>$source_file,
        );
        $arr_pathinfo = pathinfo($remote_file);
        $remote_path = isset($arr_pathinfo['dirname']) ? $arr_pathinfo['dirname'] : '';
        $remote_file_name = (isset($arr_pathinfo['dirname']) && strlen($arr_pathinfo['dirname']) >0) ? $arr_pathinfo['dirname'] : '';
        if(strlen($remote_file_name)<1)
        {
            return $this->make_right_data($arr_data);
        }
        $result_make_dir = $this->make_dir($remote_path);
        if($result_make_dir['ret'] !=0)
        {
            return $result_make_dir;
        }
        if(!@ftp_chdir($this->ftp_conn,$remote_path))
        {
            $this->set_error_desc("ftp_chdir失败:地址[{$this->host}]端口:[{$this->port}]账号:[{$this->user}]密码:[{$this->password}]");
         	return $this->make_error_data();
        }
        if(!@ftp_pasv($this->ftp_conn,true))
        {
            $this->set_error_desc("ftp_pasv被动模式设置失败:地址[{$this->host}]端口:[{$this->port}]账号:[{$this->user}]密码:[{$this->password}]");
         	return $this->make_error_data();
        }
        $ftp_put = ftp_put($this->ftp_conn,$remote_file,$source_file,FTP_BINARY);
        if(!$ftp_put)
        {
 			$this->set_error_desc("ftp_put上传文件失败:地址[{$this->host}]端口:[{$this->port}]账号:[{$this->user}]密码:[{$this->password}]远程路径:[{$remote_path}]远程文件[{$remote_file}]本地文件[{$source_file}]");
 			return $this->make_error_data();
        }
        return $this->make_right_data($arr_data);
    }
    
    
    /**
     * 上传文件
     */
    public function create_file_dir($remote_file,$source_file)
    {
        $remote_file = str_replace('//','/',$remote_file);
        $source_file = str_replace('//','/',$source_file);
        $arr_data = array(
            'remote_path'=>$remote_file,
            'source_file'=>$source_file,
        );
        $arr_pathinfo = pathinfo($remote_file);
        $remote_path = isset($arr_pathinfo['dirname']) ? $arr_pathinfo['dirname'] : '';
        $remote_file_name = (isset($arr_pathinfo['dirname']) && strlen($arr_pathinfo['dirname']) >0) ? $arr_pathinfo['dirname'] : '';
        if(strlen($remote_file_name)<1)
        {
            return $this->make_right_data($arr_data);
        }
        $result_make_dir = $this->make_dir($remote_path);
        return $result_make_dir;
    }
    
    
    /**
     * 检查文件是否存在
     * @param unknown $path
     * @return multitype:number
     */
    public function check_file_exsist($path)
    {
        $path = trim(ltrim(ltrim($path,'/'),'\\'));
        if(strlen($path) <1)
        {
            $this->set_error_desc("文件相对路径为空[{$path}]");
 			return $this->make_error_data();
        }
        $arr_pathinfo = pathinfo($path);
        if(!isset($arr_pathinfo['extension']) || strlen($arr_pathinfo['extension']) <1)
        {
            $this->set_error_desc("文件扩展名为空[{$path}]");
            return $this->make_error_data();
        }
        //获取ftp资源流
        $result_base = $this->base_opration_ftp();
        if(!$result_base)
        {
            return $this->make_error_data();
        }
        $file_size = ftp_size($this->ftp_conn,$path);
        $file_size = (int)$file_size;
        if ($file_size>0)
        {
            return $this->make_right_data($file_size);
        }
        $this->set_error_desc("文件相对路径为空[{$path}]文件大小[{$file_size}]");
        return $this->make_error_data();
    }
    
    public function my_destruct()
    {
        if(is_null($this->ftp_conn) || !is_object($this->ftp_conn))
        {
            return ;
        }
        @ftp_close($this->ftp_conn);
    }

    //已扫描文件标志位
    private $str_scan_flag_name = 'scan_flag.txt';
    /**
     * 定制化：孝乐落地 - 定时扫描FTP媒资文件，过滤已删除的文件夹（仅验证一级目录）
     * @param string $ftp_url      FTP基地址
     * @param string $str_ftp_path CP配置的FTP目录基地址
     * @return array
     */
    public function get_valid_recursive_path($ftp_url,$str_ftp_path)
    {
        $str_ftp_ret = '';
        //获取路径下的所有一级目录
        $arr_contents = ftp_nlist($this->ftp_conn, $str_ftp_path);
        if(is_array($arr_contents) && !empty($arr_contents))
        {
            //遍历验证是否已经被扫描
            foreach($arr_contents as $content)
            {
                if(is_dir($ftp_url . $content))
                {
                    $str_flag_file = rtrim($content,'/') . '/' . $this->str_scan_flag_name;
                    $obj_file_content = @file_get_contents($ftp_url . $str_flag_file);
                    //如果不存在，创建
                    if($obj_file_content === false)
                    {
                        $str_ftp_ret = $content;
                        //创建标志位文件
                        $this->modify_valid_flag_file($content);
                        break;
                    }
                    else
                    {
                        if(empty($obj_file_content))
                        {
                            $str_ftp_ret = ''; break;
                        }
                    }
                }
            }
        }
        return $str_ftp_ret;
    }

    
    public function ftp_get_to_local($local_file,$remote_file,$mode=FTP_BINARY)
    {
        //获取ftp资源流
        $result_base = $this->base_opration_ftp();
        if(!$result_base)
        {
            return $this->make_error_data();
        }
        $result =ftp_get($this->ftp_conn, $local_file, $remote_file, $mode);
        if(!$result)
        {
            $this->set_error_desc("ftp_get下载文件失败:地址[{$this->host}]端口:[{$this->port}]账号:[{$this->user}]密码:[{$this->password}]远程路径:[{$remote_file}]模式[{$mode}]本地文件[{$local_file}]");
 			return $this->make_error_data();
        }
        return $this->make_right_data($local_file);
    }
    
    /**
     * 创建标识文件夹已被扫描的文件标志位
     */
    public function modify_valid_flag_file($str_ftp_path,$str_content = 0)
    {
        $str_file_path = rtrim(dirname(__FILE__),'/') . '/' . $this->str_scan_flag_name;
        if(!file_exists($str_file_path))
        {
            $obj_file = fopen($str_file_path,'w');
            fclose($obj_file);
        }
        @file_put_contents($str_file_path,$str_content); @chmod($str_file_path,0777);
        //FTP文件路径
        $str_ftp_path = rtrim($str_ftp_path,'/') . '/' . $this->str_scan_flag_name;
        //删除原始文件
        if($str_content == 1)
        {
            $this->delete_ftp_file($str_ftp_path);
        }
        //上传到FTP
        $arr_ret = $this->upload_file($str_ftp_path,$str_file_path);
        if($arr_ret['ret'] == 0)
        {
            @ftp_chmod($this->ftp_conn,0777,$str_ftp_path);
            @unlink($str_file_path);
        }
    }

    /**
     * 获取FTP连接对象
     */
    public function get_ftp_conn()
    {
        return $this->ftp_conn;
    }

}